/*
 * Copyright (C) 2008 Peter Kling
 * 
 * This file is part of 'A Kind of Billiard', a graphical billiard simulation.
 * 
 * 'A Kind of Billiard' is free software: you can redistribute it and/or modify it under the terms of the GNU General
 * Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 * 
 * 'A Kind of Billiard' is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with 'A Kind of Billiard'. If not, see
 * <http://www.gnu.org/licenses/>.
 */

package de.akob.modeling;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

import javax.media.opengl.GL;

import de.akob.mathematics.MathVector;

/**
 * This class loads models from .mdl files. The mdl file format is a customized version of the Wavefront Object file
 * format (.obj files).
 * 
 * TODO: description of the customized file format
 */
public class MDLObjectLoader {
	/**
	 * Loads objects from the given file.
	 * 
	 * @param gl OpenGL object used for drawing
	 * @param fileName filename of model file
	 * @return <code>Model</code> object for the model (or null if the model could not be loaded)
	 */
	public static Model loadModel(GL gl, String fileName) {
		// object data (used to create GLObject instance)
		ArrayList<ArrayList<Integer>> faces = new ArrayList<ArrayList<Integer>>();
		ArrayList<Vertex> vertices = new ArrayList<Vertex>();
		ArrayList<MathVector> normals = new ArrayList<MathVector>();
		
		// start reading file
		BufferedReader bufferedReader;
		String line;
		int line_nr = 0;
		try {
			bufferedReader = new BufferedReader(new FileReader(new File(fileName)));
			while ((line = bufferedReader.readLine()) != null) {
				line_nr++;
				String[] tokens = line.trim().replaceAll("[\\s]+", " ").split(" ");
				String type = tokens[0];
				
				// vertex data
				if (type.equals("vertex")) {
					if (tokens.length != 4) {
						System.err.print("Warning: skipping vertex (vertex must have exactly three components)");
						System.err.println(" --> skipped line " + line_nr);
						continue;
					}
					Vertex vertex = new Vertex(Double.parseDouble(tokens[1]), Double.parseDouble(tokens[2]), Double
					        .parseDouble(tokens[3]));
					vertices.add(vertex);
					continue;
				}
				
				// normal data
				if (type.equals("normal")) {
					if (tokens.length != 4) {
						System.err.print("Warning: skipping normal (normal must have exactly three components)");
						System.err.println(" --> skipped line " + line_nr);
						continue;
					}
					MathVector normal = new MathVector(Double.parseDouble(tokens[1]), Double.parseDouble(tokens[2]),
					        Double.parseDouble(tokens[3]));
					normals.add(normal);
					continue;
				}
				
				// face data
				if (type.equals("face")) {
					int faceLength = tokens.length - 1;
					ArrayList<Integer> face = new ArrayList<Integer>();
					for (int i = 0; i < faceLength; i++)
						face.add(Integer.parseInt(tokens[i + 1]) - 1);
					faces.add(face);
					continue;
				}
				
				// comments
				if (type.equals("") || type.charAt(0) == '#')
					continue;
				
				// unknown command
				System.err.print("Warning: unknown command ('" + type + "')");
				System.err.println(" --> skipped line " + line_nr);
			}
			bufferedReader.close();
		} catch (FileNotFoundException e) {
			System.err.println("FileNotFoundException: " + e.getLocalizedMessage());
			return null;
		} catch (NumberFormatException e) {
			System.err.println("NumberFormatException (line " + line_nr + "): " + e.getLocalizedMessage());
			return null;
		} catch (IOException e) {
			System.err.println("IOException (line " + line_nr + "): " + e.getMessage());
			return null;
		}
		
		// sanity checks
		if (normals.size() > 0 && normals.size() != faces.size()) {
			System.err.println("Error: the number of faces and normals must match");
			return null;
		}
		
		// create model
		Model model;
		if (normals.size() > 0)
			model = new Model(vertices, faces, normals);
		else
			model = new Model(vertices, faces);
		
		// return model
		return model;
	}
}
